#ifndef CREMOTEVOICE_H
#define CREMOTEVOICE_H

#include <QObject>
#include <QAudio>     //这五个是QT处理音频的库
#include <QAudioFormat>
#include <QAudioInput>
#include <QAudioOutput>
#include <QIODevice>
#include <QTimer>
#include <QHash>
#include <QVector>
#include <QUdpSocket>
#include <QFile>
#include <QDateTime>
#include <QCamera>
//#include <QCameraViewfinder>
#include <QCameraImageCapture>

#include "../network/ikcp.h"

#ifdef ENABLEREMOTEVOICE

extern "C"{
    #include "avilib.h"
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    #include "libavdevice/avdevice.h"
    #include "libavformat/avio.h"
    #include "libavutil/imgutils.h"
}

/*
 * CRemoteVoice
 *
 * 用于局域网下实时视频语音通讯，采用kcp协议，不是c/s模式，没有服务器。
 *
 * 使用方法如下：
 *
 * CRemoteVoice m_RemoteVoice;
 *
 * private slots:
 *   void processcameraImageCaptured(int id,QImage image);
 *   /// 处理收到的客户端信息
 *   void processClientReceiveMsg(CRemoteClient* rclient,QByteArray datagramdata);
 *
 *   m_RemoteVoice.InitAudioInputAndOutput();
 *   m_RemoteVoice.InitVideoInput();
 *
 *   connect(&m_RemoteVoice,SIGNAL(signal_cameraImageCaptured(int,QImage)),this,SLOT(processcameraImageCaptured(int,QImage)));
 *   connect(&m_RemoteVoice,SIGNAL(signal_ClientReceiveMsg(CRemoteClient*,QByteArray)),this,SLOT(processClientReceiveMsg(CRemoteClient*,QByteArray)));
 *
 *   m_RemoteVoice.setRecivePort(ui->lineEdit_3->text().toInt());
 *   m_RemoteVoice.addClient(QHostAddress(ui->lineEdit->text()),ui->lineEdit_2->text().toInt());
 *
 * /// 处理收到的客户端信息
 *   void MainWindow::processClientReceiveMsg(CRemoteClient* rclient,QByteArray datagramdata)
 *   {
 *       QImage img;
 *
 *       if(img.loadFromData(datagramdata))
 *           ui->label->setPixmap(QPixmap::fromImage(img));
 *   }
 *
 * void MainWindow::processcameraImageCaptured(int id,QImage image)
 *   {
 *       ui->label->setPixmap(QPixmap::fromImage(image));
 *   }
 */

/**
 * @brief The tagVoiceSection struct 音频数据备份结构
 */
struct tagVoiceSection
{
    tagVoiceSection()
        : Originallength(0),Compressionlegth(0),recordtime(0)
    {

    }
    tagVoiceSection(qint32 ol,qint32 cl,qint64 rt)
        : Originallength(ol),Compressionlegth(cl),recordtime(rt)
    {

    }

    qint32 Originallength;           // 数据原始长度
    qint32 Compressionlegth;         // 压缩后长度
    qint64 recordtime;               // 记录时间
};

/**
 * @brief The tagMultiType enum    数据类型
 */
enum tagMultiType
{
    MULTITYPE_AUDIO = 0,          // 音频数据
    MULTITYPE_VIDEO,              // 视频数据
    MULTITYPE_SCREEN,             // 屏幕数据
    MULTITYPE_NULL
};

#pragma pack(push,1)
struct tagMultiDataHearder
{
    tagMultiType datatype;               // 数据类型
    qint64 sourcesize;                   // 原始数据大小
    qint64 compresssize;                 // 压缩后数据大小
};
#pragma pack(pop)

class CRemoteClient : public QObject
{
    Q_OBJECT

public:
    explicit CRemoteClient(QObject *parent = nullptr,QUdpSocket *pUdpSocket=NULL);
    ~CRemoteClient(void);

    /// 设置udpsocket
    inline void setUdpSocket(QUdpSocket *pudpsocket) { m_UdpSocket = pudpsocket; }
    /// 得到udpsocket
    inline QUdpSocket* getUdpSocket(void) { return m_UdpSocket; }
    /// 设置要连接的地址和端口
    void SetClientInfo(QHostAddress address,int port);
    /// 得到名称
    inline QString getName(void) { return m_Name; }
    /// 发送报文(KCP使用)
    int SendKcpData(QByteArray Datagramdata);

    /// 处理发送报文
    qint64 onProcessSendData(const char * buf, int len);
    /// kcp处理接收到的报文
    void onProcessReciverKcpDatagramdata(QByteArray& Datagramdata);
    /// kcp更新
    void kcp_update(void);

private:
    /// 处理数据发送
    void processdatasend(void);
    /// 处理数据接收
    void processdatarecive(void);

signals:
    /// 处理接收到的消息
    void processPendingDatagram(CRemoteClient* rclient,QByteArray datagramdata);

private:
    QUdpSocket *m_UdpSocket;
    QString m_Name;
    QHostAddress m_address;
    int m_port;
    QByteArray m_datasendBuffer;                 /**< 数据发送缓冲区 */

    QByteArray m_datareciveBuffer;               /**< 数据接收缓冲区 */
    bool       m_isdatareiveHearder;             /**< 是否接收到一个新的文件 */
    tagMultiDataHearder m_datareiveHearder;      /**< 接收文件的头 */
    QByteArray m_reciverFileBuffer;              /**< 接收到的文件缓冲区 */

    /*
    kcp mode :
    0: default
    1: normal
    2: first
    */
    static const int s_RT_KCP_MODE = 0;
    static const int s_RT_MTU = 10000;
    static const int s_RT_max_send_que = 100000;

    ikcpcb *m_ikcp;
};

/**
 * @brief The CRemoteVoice class 用于远程语音交互
 */
class CRemoteVoice : public QObject
{
    Q_OBJECT

public:
    explicit CRemoteVoice(QObject *parent = nullptr,int receivePort=-1);
    ~CRemoteVoice();

    /// 设置数据接收端口
    void setRecivePort(int port);
    /// 得到数据接收端口
    inline int getRecivePort(void) { return m_receivePort; }

    /// 初始化音频输入输出设备
    bool InitAudioInputAndOutput(bool isRecord=false);
    /// 初始化视频输入设备
    bool InitVideoInput(int refreshfrequency=100,int screenWidth=640,int screenHeight=360,bool isRecord=false);
    /// 初始化屏幕输入设备
    bool InitScreenInput(int framerate=5,QString deviceType="gdigrab",int screenWidth=640,int screenHeight=360,bool isRecord=false);

    /// 打开摄像头
    void openCamera(void);
    /// 关闭摄像头
    void closeCamera(void);

    /// 打开录屏
    void openScreenCapture(void);
    /// 关闭录屏
    void closeScreenCapture(void);

    /// 设置是否发送语音数据
    inline void setIsSendVoiceData(bool isSend) { m_issendvoicedata = isSend; }
    /// 得到是否发送语音数据
    inline bool isSendVoiceData(void) { return m_issendvoicedata; }
    /// 设置是否记录语音数据
    inline void setIsRecordVoiceData(bool isRecord) { m_isrecordvoicedata = isRecord; }
    /// 得到是否记录语音数据
    inline bool isRecordVoiceData(void) { return m_isrecordvoicedata; }
    /// 设置语音记录目录
    inline void setVoiceRecordCatalogue(QString catalogue) { m_recordvoicecatalogue = catalogue; }
    /// 得到语音记录目录
    inline QString getVoiceRecordCatalogue(void) { return m_recordvoicecatalogue; }

    /// 设置是否记录视频数据
    inline void setIsRecordVideoData(bool isRecord) { m_isrecordvideodata = isRecord; }
    /// 得到是否记录语音数据
    inline bool isRecordVideoData(void) { return m_isrecordvideodata; }

    /// 添加一个客户端
    bool addClient(QHostAddress address,int port);
    /// 添加一个客户端
    bool addClient2(CRemoteClient *pClient);
    /// 删除一个客户端
    void delClient(QString pName);
    /// 得到一个客户端
    CRemoteClient* getClient(QString pName);
    /// 删除所有的客户端
    void deleteAllClients(void);
    /// 得到所有的客户端
    inline QHash<QString,CRemoteClient*>& getAllClients(void) { return m_RemoteClients; }

    /// 转换摄像头图像为byte数据
    void ConvertImageToBytes(const QImage& image);

private:
    /// 得到语音记录文件完整路径
    QString getVoiceRecordFilePath(tagMultiType multitype=MULTITYPE_AUDIO);
    /// 处理语音记录
    void processvoicerecord(void);
    /// 处理视频记录
    void processvideorecord(void);

signals:
    /// 处理收到的客户端信息
    void signal_ClientReceiveMsg(CRemoteClient* rclient,QByteArray datagramdata);
    /// 处理摄像头捕获图像消息
    void signal_cameraImageCaptured(int id,QImage image);
    /// 摄像头图像转换bytes完成
    void signal_convertImageToBytes(QByteArray imgData);
    /// 处理屏幕捕获图像消息
    void signal_screenImageCaptured(QImage image);

public slots:
    void handleStateChanged_input(QAudio::State newState);
    void audio_ReadyRead();
    void reciverPendingDatagram();
    void KCPUpdate();
    void timerCamera_Update();
    void screenCamera_Update();
    void on_process_processPendingDatagram(CRemoteClient* rclient,QByteArray datagramdata);
    void processcameraImageCaptured(int id,QImage image);
    void processconvertImageToBytes(QByteArray imgData);

private:
    QUdpSocket m_UdpSocket;
    QTimer m_updateTimer;

    int m_receivePort;
    QHash<QString,CRemoteClient*> m_RemoteClients;    /**< 存储所有的远程客户端 */

    QAudioInput   *m_audio_in;               /**< 用于音频输入 */
    QAudioOutput  *m_audio_out;              /**< 用于音频输出 */
    QIODevice     *m_audio_streamIn;
    QIODevice     *m_audio_out_streamIn;

    bool          m_issendvoicedata;         /**< 是否发送语音数据 */
    bool          m_isrecordvoicedata;       /**< 是否记录语音数据 */
    QString       m_recordvoicecatalogue;    /**< 语音数据记录文件夹 */
    QFile         m_recordvoicefile;         /**< 语音记录文件 */
    QDateTime     m_currentRecordTime;       /**< 当前记录音频时间 */
    QDateTime     m_currentVideoRecordTime;  /**< 当前记录视频时间 */

    QCamera             *m_camera;           /**< 系统摄像头 */
    //QCameraViewfinder   *m_cameraviewfinder;   /**< 摄像头取景器部件 */
    QCameraImageCapture *m_cameraImageCapture; /**< 截图部件 */
    QTimer        m_timerCamera;             /**< 摄像头刷新定时器 */

    /** 用于屏幕录制 */
    AVFormatContext *m_formatContext;
    AVCodecParameters *m_codecParameters;
    int m_videoIndex;
    AVCodecContext *m_codecContext;
    AVPacket *m_packet;
    AVFrame *m_frame;
    SwsContext *m_imgConvertContext;
    QTimer        m_creentCamera;             /**< 屏幕录制刷新定时器 */
    QImage   m_screenImage;                   /**< 用于存储屏幕截图 */
    int      m_screenWidth,m_screenHeight,m_refreshframe;
    bool     m_isrecordvideodata;             /**< 是否记录视频数据 */
    int      m_lineSize[4];
    avi_t    *m_out_video_fd;                 /**< avilib库中定义的文件数据结构 */
};

#endif

#endif // CREMOTEVOICE_H
